// Copyright (c) MatrixFramework. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace MatrixFramework.Photos.Domain.Entities;

/// <summary>
/// 照片批量操作项实体
/// </summary>
public class PhotoBatchOperationItem : FullAuditedEntity<Guid>, IMultiTenant
{
    /// <summary>
    /// 租户ID
    /// </summary>
    public virtual Guid? TenantId { get; protected set; }

    /// <summary>
    /// 批量操作ID
    /// </summary>
    public virtual Guid BatchOperationId { get; protected set; }

    /// <summary>
    /// 照片ID
    /// </summary>
    public virtual Guid PhotoId { get; protected set; }

    /// <summary>
    /// 操作状态
    /// </summary>
    public virtual BatchItemStatus Status { get; protected set; }

    /// <summary>
    /// 操作参数
    /// </summary>
    public virtual string? Parameters { get; protected set; }

    /// <summary>
    /// 操作结果
    /// </summary>
    public virtual string? Result { get; protected set; }

    /// <summary>
    /// 错误信息
    /// </summary>
    [MaxLength(1000)]
    public virtual string? ErrorMessage { get; protected set; }

    /// <summary>
    /// 开始时间
    /// </summary>
    public virtual DateTime? StartedAt { get; protected set; }

    /// <summary>
    /// 完成时间
    /// </summary>
    public virtual DateTime? CompletedAt { get; protected set; }

    /// <summary>
    /// 处理时长（毫秒）
    /// </summary>
    public virtual long ProcessingTimeMs { get; protected set; }

    /// <summary>
    /// 重试次数
    /// </summary>
    public virtual int RetryCount { get; protected set; }

    /// <summary>
    /// 最大重试次数
    /// </summary>
    public virtual int MaxRetryCount { get; protected set; }

    /// <summary>
    /// 关联批量操作
    /// </summary>
    public virtual PhotoBatchOperation BatchOperation { get; protected set; } = null!;

    #region 构造函数

    /// <summary>
    /// 参数化构造函数
    /// </summary>
    /// <param name="id">操作项ID</param>
    /// <param name="tenantId">租户ID</param>
    /// <param name="batchOperationId">批量操作ID</param>
    /// <param name="photoId">照片ID</param>
    /// <param name="parameters">操作参数</param>
    public PhotoBatchOperationItem(
        Guid id,
        Guid? tenantId,
        Guid batchOperationId,
        Guid photoId,
        string? parameters = null) : base(id)
    {
        TenantId = tenantId;
        BatchOperationId = batchOperationId;
        PhotoId = photoId;
        Parameters = parameters;
        Status = BatchItemStatus.Pending;
        MaxRetryCount = 3; // 默认最大重试3次
    }

    /// <summary>
    /// 无参构造函数（用于EF Core）
    /// </summary>
    protected PhotoBatchOperationItem()
    {
    }

    #endregion

    #region 业务方法

    /// <summary>
    /// 开始处理
    /// </summary>
    public virtual void Start()
    {
        if (Status != BatchItemStatus.Pending && Status != BatchItemStatus.Retrying)
        {
            throw new InvalidOperationException("只能对待处理或重试状态的项目开始处理");
        }

        Status = BatchItemStatus.Processing;
        StartedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// 完成处理
    /// </summary>
    /// <param name="result">处理结果</param>
    public virtual void Complete(string? result = null)
    {
        if (Status != BatchItemStatus.Processing)
        {
            throw new InvalidOperationException("只能对处理中状态的项目完成处理");
        }

        Status = BatchItemStatus.Completed;
        CompletedAt = DateTime.UtcNow;
        Result = result;

        if (StartedAt.HasValue)
        {
            ProcessingTimeMs = (long)(CompletedAt.Value - StartedAt.Value).TotalMilliseconds;
        }
    }

    /// <summary>
    /// 处理失败
    /// </summary>
    /// <param name="errorMessage">错误信息</param>
    public virtual void Fail(string errorMessage)
    {
        if (Status != BatchItemStatus.Processing)
        {
            throw new InvalidOperationException("只能对处理中状态的项目设置失败");
        }

        Status = BatchItemStatus.Failed;
        CompletedAt = DateTime.UtcNow;
        ErrorMessage = errorMessage;
        RetryCount++;

        if (StartedAt.HasValue)
        {
            ProcessingTimeMs = (long)(CompletedAt.Value - StartedAt.Value).TotalMilliseconds;
        }
    }

    /// <summary>
    /// 跳过处理
    /// </summary>
    /// <param name="reason">跳过原因</param>
    public virtual void Skip(string reason)
    {
        if (Status != BatchItemStatus.Processing)
        {
            throw new InvalidOperationException("只能对处理中状态的项目跳过");
        }

        Status = BatchItemStatus.Skipped;
        CompletedAt = DateTime.UtcNow;
        ErrorMessage = reason;
    }

    /// <summary>
    /// 标记为重试
    /// </summary>
    public virtual void MarkForRetry()
    {
        if (Status != BatchItemStatus.Failed)
        {
            throw new InvalidOperationException("只能对失败状态的项目标记重试");
        }

        if (RetryCount >= MaxRetryCount)
        {
            throw new InvalidOperationException($"已达到最大重试次数({MaxRetryCount})");
        }

        Status = BatchItemStatus.Retrying;
        StartedAt = null;
        CompletedAt = null;
        ProcessingTimeMs = 0;
    }

    /// <summary>
    /// 检查是否可以重试
    /// </summary>
    /// <returns>是否可以重试</returns>
    public virtual bool CanRetry()
    {
        return Status == BatchItemStatus.Failed && RetryCount < MaxRetryCount;
    }

    /// <summary>
    /// 设置最大重试次数
    /// </summary>
    /// <param name="maxRetryCount">最大重试次数</param>
    public virtual void SetMaxRetryCount(int maxRetryCount)
    {
        MaxRetryCount = Math.Max(0, maxRetryCount);
    }

    #endregion
}

/// <summary>
/// 批量操作项状态枚举
/// </summary>
public enum BatchItemStatus
{
    /// <summary>
    /// 待处理
    /// </summary>
    Pending = 0,

    /// <summary>
    /// 处理中
    /// </summary>
    Processing = 1,

    /// <summary>
    /// 已完成
    /// </summary>
    Completed = 2,

    /// <summary>
    /// 失败
    /// </summary>
    Failed = 3,

    /// <summary>
    /// 跳过
    /// </summary>
    Skipped = 4,

    /// <summary>
    /// 重试中
    /// </summary>
    Retrying = 5
}